// ==UserScript==
// @name         Viper Title Copy Button
// @version      1.0
// @description  Copy post title to clipboard
// @author       You
// @match        https://viper.to/threads/*
// @match        https://vipergirls.to/threads/*
// @match        https://planetviper.club/threads/*
// @match        https://viperbb.rocks/threads/*
// @match        https://viperkats.eu/threads/*
// @match        https://viperohilia.art/threads/*
// @match        https://viperproxy.org/threads/*
// @match        https://vipervault.link/threads/*
// @grant        GM_setClipboard
// @grant        GM_addStyle
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    const CONFIG = {
        colors: {
            primary: '#afc953',
            secondary: '#597c18',
            hoverPrimary: '#9db848',
            hoverSecondary: '#4a6a14',
            success: '#22c55e',
            error: '#ef4444',
        },
        button: {
            size: 34,
            iconSize: 16,
            borderRadius: 10,
        },
        animation: {
            duration:200,
            feedbackDuration: 510,
        },
    };

    const IMAGE_HOSTS = [
        'vipr.im', 'imx.to', 'turboimagehost.com', 'imagebam.com',
        'imgbox.com', 'pixhost.to', 'imagevenue.com', 'pimpandhost.com',
        'img.yt', 'imagetwist.com', 'acidimg.cc'
    ];

    const IMAGE_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.gif', '.webp'];

    const ICONS = {
        copy: `<svg xmlns="http://www.w3.org/2000/svg" width="${CONFIG.button.iconSize}" height="${CONFIG.button.iconSize}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <rect width="14" height="14" x="8" y="8" rx="2" ry="2"/>
            <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/>
        </svg>`,
        check: `<svg xmlns="http://www.w3.org/2000/svg" width="${CONFIG.button.iconSize}" height="${CONFIG.button.iconSize}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
            <polyline points="20 6 9 17 4 12"/>
        </svg>`,
        error: `<svg xmlns="http://www.w3.org/2000/svg" width="${CONFIG.button.iconSize}" height="${CONFIG.button.iconSize}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
            <line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
        </svg>`,
    };

    const injectStyles = () => {
        const { colors, button, animation } = CONFIG;

        GM_addStyle(`
            .p-title-value {
                display: inline !important;
            }

            .viper-copy-btn {
                display: inline-flex;
                align-items: center;
                justify-content: center;
                width: ${button.size}px;
                height: ${button.size}px;
                padding: 0;
                margin-left: 12px;
                background: linear-gradient(145deg, ${colors.primary}, ${colors.secondary});
                color: white;
                border: none;
                border-radius: ${button.borderRadius}px;
                cursor: pointer;
                box-shadow:
                    0 2px 8px rgba(89, 124, 24, 0.3),
                    0 1px 2px rgba(0, 0, 0, 0.1),
                    inset 0 1px 0 rgba(255, 255, 255, 0.2);
                transition: all ${animation.duration}ms cubic-bezier(0.4, 0, 0.2, 1);
                flex-shrink: 0;
                position: relative;
                overflow: hidden;
                vertical-align: middle;
            }

            .viper-copy-btn::before {
                content: '';
                position: absolute;
                inset: 0;
                background: linear-gradient(145deg, rgba(255,255,255,0.15), transparent);
                border-radius: inherit;
                pointer-events: none;
            }

            .viper-copy-btn:hover {
                background: linear-gradient(145deg, ${colors.hoverPrimary}, ${colors.hoverSecondary});
                transform: translateY(-2px);
                box-shadow:
                    0 4px 16px rgba(89, 124, 24, 0.4),
                    0 2px 4px rgba(0, 0, 0, 0.15),
                    inset 0 1px 0 rgba(255, 255, 255, 0.25);
            }

            .viper-copy-btn:active {
                transform: translateY(0) scale(0.95);
                box-shadow:
                    0 1px 4px rgba(89, 124, 24, 0.3),
                    inset 0 1px 2px rgba(0, 0, 0, 0.1);
            }

            .viper-copy-btn--success {
                background: linear-gradient(145deg, ${colors.success}, #16a34a) !important;
                box-shadow: 0 2px 12px rgba(34, 197, 94, 0.4) !important;
            }

            .viper-copy-btn--error {
                background: linear-gradient(145deg, ${colors.error}, #dc2626) !important;
                box-shadow: 0 2px 12px rgba(239, 68, 68, 0.4) !important;
            }

            .viper-copy-btn svg {
                transition: transform ${animation.duration}ms ease;
            }

            .viper-copy-btn:hover svg {
                transform: scale(1.1);
            }

            .viper-copy-btn--animate {
                animation: viper-pop ${animation.duration * 2}ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
            }

            @keyframes viper-pop {
                0% { transform: scale(1); }
                50% { transform: scale(1.15); }
                100% { transform: scale(1); }
            }

            .viper-copy-btn[data-tooltip] {
                position: relative;
            }

            .viper-copy-btn[data-tooltip]::after {
                content: attr(data-tooltip);
                position: absolute;
                bottom: calc(100% + 8px);
                left: 50%;
                transform: translateX(-50%) scale(0.8);
                padding: 6px 10px;
                background: rgba(0, 0, 0, 0.85);
                color: white;
                font-size: 12px;
                font-weight: 500;
                white-space: nowrap;
                border-radius: 6px;
                opacity: 0;
                visibility: hidden;
                transition: all ${animation.duration}ms ease;
                pointer-events: none;
                z-index: 1000;
                box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
            }

            .viper-copy-btn[data-tooltip]:hover::after {
                opacity: 1;
                visibility: visible;
                transform: translateX(-50%) scale(1);
            }
        `);
    };

    const hasImages = () => {
        const contentSelectors = [
            '.message-body',
            '.bbWrapper',
            '.message-content',
            'article.message-body',
            '.post-content'
        ];

        let contentArea = null;
        for (const selector of contentSelectors) {
            contentArea = document.querySelector(selector);
            if (contentArea) break;
        }

        const searchScope = contentArea || document;

        const hasImageHost = IMAGE_HOSTS.some(host =>
            searchScope.querySelector(`a[href*="${host}"]`)
        );
        if (hasImageHost) return true;

        const hasDirectImage = IMAGE_EXTENSIONS.some(ext =>
            searchScope.querySelector(`img[src*="${ext}"], a[href*="${ext}"]`)
        );
        return hasDirectImage;
    };

    const getThreadTitle = () => {
        const selectors = [
            'h1.p-title-value',
            '.p-title .p-title-value',
            'h1.thread-title',
            '.p-title > h1',
            'h1'
        ];

        for (const selector of selectors) {
            const el = document.querySelector(selector);
            if (el) {
                return el.textContent
                    .trim()
                    .replace(/^Thread:\s*/i, '')
                    .replace(/\s*[-|]\s*Viper.*$/i, '')
                    .trim();
            }
        }

        return document.title
            .replace(/\s*[-|]\s*Viper.*$/i, '')
            .replace(/\s*[-|][^-|]*$/, '')
            .trim() || 'Untitled Thread';
    };

    const setButtonState = (button, state) => {
        const states = {
            default: { icon: ICONS.copy, class: '', tooltip: 'Copy title' },
            success: { icon: ICONS.check, class: 'viper-copy-btn--success', tooltip: 'Copied!' },
            error: { icon: ICONS.error, class: 'viper-copy-btn--error', tooltip: 'Failed!' },
        };

        const { icon, class: className, tooltip } = states[state];

        button.innerHTML = icon;
        button.className = `viper-copy-btn ${className}`.trim();
        button.dataset.tooltip = tooltip;

        if (state !== 'default') {
            button.classList.add('viper-copy-btn--animate');
        }
    };

    const createCopyButton = () => {
        const button = document.createElement('button');
        button.className = 'viper-copy-btn';
        button.innerHTML = ICONS.copy;
        button.dataset.tooltip = 'Copy title';
        button.type = 'button';

        button.addEventListener('click', async (e) => {
            e.preventDefault();
            e.stopPropagation();

            const title = getThreadTitle();

            try {
                if (navigator.clipboard && navigator.clipboard.writeText) {
                    await navigator.clipboard.writeText(title);
                } else {
                    GM_setClipboard(title, 'text');
                }
                setButtonState(button, 'success');
            } catch (err) {
                console.error('Copy failed:', err);
                try {
                    GM_setClipboard(title, 'text');
                    setButtonState(button, 'success');
                } catch (fallbackErr) {
                    setButtonState(button, 'error');
                }
            }

            setTimeout(() => {
                setButtonState(button, 'default');
            }, CONFIG.animation.feedbackDuration);
        });

        return button;
    };

    const insertButton = () => {
        if (!hasImages() || document.querySelector('.viper-copy-btn')) return;

        const button = createCopyButton();

        const titleEl = document.querySelector(
            '.p-title-value, h1.thread-title, .thread-title-text'
        ) || document.querySelector('h1');

        if (!titleEl) return;

        const wrapper = document.createElement('span');
        wrapper.style.display = 'inline-flex';
        wrapper.style.alignItems = 'center';

        titleEl.parentNode.insertBefore(wrapper, titleEl);
        wrapper.appendChild(titleEl);
        wrapper.appendChild(button);
    };

    const init = () => {
        injectStyles();

        const scheduleInsert = window.requestIdleCallback || ((cb) => setTimeout(cb, 100));
        scheduleInsert(insertButton);
    };

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();